#include <WiFi.h>  
#include <WebServer.h>
#include <vector>
#include <BLEDevice.h>
#include <BLEHIDDevice.h>
#include <Adafruit_SSD1306.h>
#include <fingerprint.h> 
#include <BleKeyboard.h>

BleKeyboard bleKeyboard;
const char* ssid     = "ScreenLock";
const char* password = "12345678";
const IPAddress apIP(192,168,4,1);

#define SENSOR_BAUD    115200
#define SAMPLE_COUNT   10
#define STATS_PERIOD   30000
#define MOTOR_PIN 7  // IO7 控制马达
#define SDA_PIN 0
#define SCL_PIN 1
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(128, 32, &Wire, -1);

WebServer server(80);

float samples[SAMPLE_COUNT];
int sampleIdx = 0;
int sampleCount = 0;
int displaymod=0;
struct StatPoint { unsigned long ts; float avg; };
std::vector<StatPoint> stats;

bool inside = false;
unsigned long countInside = 0;
unsigned long countOutside = 0;
unsigned int passCount = 0;

// 新增状态切换次数变量
unsigned int countInsideSwitch = 0;  
unsigned int countOutsideSwitch = 0; 

unsigned long timeInside = 0;
unsigned long timeOutside = 0;
unsigned long lastSampleTime = 0;

float customDistance = 1.3;
String fingerprintText = "";  // 默认指纹验证后输入的文本
void readSensor() {
  static String tmp;
  static bool pendingEnter = false;
  static unsigned long enterCandidateTime = 0;

  while (Serial.available()) {
    char c = Serial.read();
    if (c == '\n' || c == '\r') {
      if (tmp.startsWith("distance")) {
        float dist = tmp.substring(tmp.indexOf(':') + 1).toFloat() / 100.0;
        samples[sampleIdx] = dist;
        sampleIdx = (sampleIdx + 1) % SAMPLE_COUNT;
        if (sampleCount < SAMPLE_COUNT) sampleCount++;

        unsigned long now = millis();
        unsigned long delta = (lastSampleTime == 0) ? 0 : (now - lastSampleTime);
        lastSampleTime = now;

        if (dist <= customDistance) {
          countInside++;
          timeInside += delta;

          if (!inside) {
            if (!pendingEnter) {
              pendingEnter = true;
              enterCandidateTime = now;
            } else if (now - enterCandidateTime >= 5000) {
              // 达到 5 秒，确认进入
              pendingEnter = false;
              inside = true;
              countInsideSwitch++;

              // 显示 "use finger" 并调用指纹验证
              display.clearDisplay();
              display.setTextSize(2);
              display.setTextColor(SSD1306_WHITE);
              display.setCursor(0, 0);
              display.println("Verify");
              display.setCursor(0, 22);
              display.setTextSize(1);
              display.println("Wait press...");
              display.display();

              int fpResult = search_FP();

              display.clearDisplay();
              display.setTextSize(2);
              display.setTextColor(SSD1306_WHITE);
              display.setCursor(0, 0);
              display.println("Verify");
              display.setCursor(0, 22);
              display.setTextSize(1);
              display.println(fpResult == 1 ? "Succeed" : "Fail! Press again...");
              display.display();

                          // 调用指纹验证函数（最多3次）
             // int fpResult = 0;
              for (int attempt = 1; attempt <= 3; ++attempt) {
                fpResult = search_FP();

                display.clearDisplay();
                display.setTextSize(2);
                display.setTextColor(SSD1306_WHITE);
                display.setCursor(0, 0);
                display.println("Verify");
                display.setCursor(0, 22);
                display.setTextSize(1);

                if (fpResult == 1) {
                  display.println("Succeed");
                  display.display();

                  bleKeyboard.write(KEY_LEFT_CTRL);
                  delay(300);
                  bleKeyboard.print(fingerprintText);
                  delay(300);
                  bleKeyboard.write(KEY_RETURN);
                  delay(300);
                  break;  // 成功跳出验证流程
                } else {
                  display.println("Fail! Press again...");
                  display.display();
              
                }
              }

              if (fpResult != 1) {
                // 三次失败后算作 relax，无动作
                display.clearDisplay();
                display.setTextSize(2);
                display.setTextColor(SSD1306_WHITE);
                display.setCursor(0, 0);
                display.println("Failed");
              display.setCursor(0, 22);
              display.setTextSize(1);
              display.println("Not authorized !");
              display.display();
                //delay(2000);
              } 


              delay(2000);  // 显示2秒结果
            }
          }
        } else {
          countOutside++;
          timeOutside += delta;

          // 如果之前有进入尝试，但没满5秒，现在取消并记作干扰
          if (pendingEnter) {
            pendingEnter = false;
            passCount++;
          }

          if (inside) {
            inside = false;
            countOutsideSwitch++;

            bleKeyboard.press(KEY_LEFT_CTRL);
            bleKeyboard.press(KEY_LEFT_ALT);
            bleKeyboard.press(KEY_DELETE);
            delay(100);
            bleKeyboard.releaseAll();
            delay(500);
            bleKeyboard.write(KEY_RETURN);
            delay(500);
          }
        }

        static unsigned long lastStat = 0;
        if (now - lastStat >= 3000) {
          lastStat = now;
          float sum = 0;
          for (int i = 0; i < sampleCount; i++) sum += samples[i];
          float avg = sampleCount ? (sum / sampleCount) : 0;
          stats.push_back({ now, avg });

          while (!stats.empty() && now - stats.front().ts > STATS_PERIOD) {
            stats.erase(stats.begin());
          }
        }
      }
      tmp.clear();
    } else {
      tmp += c;
    }
  }
}


void handleRoot() {
  String html = R"rawliteral(
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <title>ScreenLock控制中心</title>
      <script>
        let customDistance = 0.5;

        async function update() {
          const res = await fetch('/data');
          const json = await res.json();

          document.getElementById('avg10').innerText = json.avg10.toFixed(2);
          document.getElementById('inside').innerText = json.timeInside;
          document.getElementById('outside').innerText = json.timeOutside;
          document.getElementById('pass').innerText = json.passCount;
          document.getElementById('insideSwitch').innerText = json.countInsideSwitch;
          document.getElementById('outsideSwitch').innerText = json.countOutsideSwitch;

          document.getElementById('currentDistance').innerText = '当前自定义距离：' + json.customDistance.toFixed(2) + ' 米';

          let points = json.stats;
          let svg = '<g stroke="#ddd" stroke-width="0.5">';
          for (let y = 0; y <= 100; y += 25) {
            svg += '<line x1="0" y1="' + y + '" x2="100" y2="' + y + '" />';
          }
          svg += '</g>';
          svg += '<g font-size="3" fill="#333">';
          svg += '<text x="0" y="5">2.0m</text>';
          svg += '<text x="0" y="30">1.5m</text>';
          svg += '<text x="0" y="55">1.0m</text>';
          svg += '<text x="0" y="80">0.5m</text>';
          svg += '<text x="0" y="99">0.0m</text>';
          svg += '</g>';
          svg += '<polyline fill="none" stroke="blue" stroke-width="2" points="';

          for (let i = 0; i < points.length; i++) {
            let x = (i / (points.length - 1)) * 100;
            let y = 100 - points[i] * 50;
            svg += x + ',' + y + ' ';
          }
          svg += '" />';
          for (let i = 0; i < points.length; i += 5) {
            let x = (i / (points.length - 1)) * 100;
            svg += '<text x="' + x + '" y="105" font-size="3" fill="#333">' + i + '</text>';
          }
          document.getElementById('graph').innerHTML = svg;
        }

        async function saveDistance() {
          let val = parseFloat(document.getElementById('distanceInput').value);
          if (isNaN(val) || val <= 0) {
            alert('请输入有效的正数距离（单位：米）');
            return;
          }
          const res = await fetch('/setDistance', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ distance: val })
          });
          if (res.ok) {
            alert('距离设置成功: ' + val + ' 米');
            document.getElementById('currentDistance').innerText = '当前自定义距离：' + val.toFixed(2) + ' 米';
            document.getElementById('distanceInput').value = '';
          } else {
            alert('设置失败');
          }
        }

        async function saveFingerprintText() {
          let val = document.getElementById('fingerprintTextInput').value;
          if (val.length === 0) {
            alert('请输入有效的文本');
            return;
          }
          const res = await fetch('/setFingerprintText', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ text: val })
          });
          if (res.ok) {
            alert('文本设置成功: ' + val);
            document.getElementById('fingerprintTextInput').value = val;
          } else {
            alert('设置失败');
          }
        }

        setInterval(update, 1000);
        window.onload = update;
      </script>
      <style>
        body {
          font-family: sans-serif;
          padding: 1rem;
          margin: 0;
          background: #f9f9f9;
        }
        h1 {
          color: #333;
        }
        .card {
          background: white;
          box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
          padding: 1rem;
          margin: 1rem 0;
          border-radius: 8px;
        }
        svg {
          background: #fff;
          border: 1px solid #ccc;
          width: 100%;
          height: 80%;
        }
        input[type="number"] {
          width: 80px;
          padding: 4px;
          margin-right: 8px;
          border: 1px solid #ccc;
          border-radius: 4px;
        }
        button {
          padding: 5px 10px;
          border: none;
          background: #007BFF;
          color: white;
          border-radius: 4px;
          cursor: pointer;
        }
        button:hover {
          background: #0056b3;
        }
        @media (max-width: 600px) {
          body {
            font-size: 14px;
          }
        }
      </style>
    </head>
    <body>
      <h1>ScreenLock控制中心</h1>
 <p>版本号: v1.0</p>
      <div class="card">
        <div id="currentDistance">当前自定义距离：0.50 米</div>
        <label>自定义距离 (米): </label>
        <input type="number" id="distanceInput" step="0.01" min="0.01" value="" />
        <button onclick="saveDistance()">保存</button>
      </div>

      <div class="card">
        <div>指纹验证后输入的文本:</div>
        <input type="text" id="fingerprintTextInput" />
        <button onclick="saveFingerprintText()">保存</button>
      </div>

      <div class="card">
        10样本平均距离：<strong><span id="avg10">--</span> m</strong>
      </div>

      <div class="card">
        <svg id="graph" viewBox="0 0 100 110" preserveAspectRatio="none"></svg>
      </div>

      <div class="card">
        <strong>工作时长：</strong><span id="inside">--</span> 秒<br />
        <strong>休息时长：</strong><span id="outside">--</span> 秒<br />
        <strong>在岗次数：</strong><span id="insideSwitch">--</span><br />
        <strong>离岗次数：</strong><span id="outsideSwitch">--</span><br />
        <strong>经过次数：</strong><span id="pass">--</span>
      </div>
    </body>
    </html>
  )rawliteral";
  server.send(200, "text/html", html);
}

void handleData() {
  float sum = 0;
  for (int i = 0; i < sampleCount; i++) sum += samples[i];
  float avg10 = sampleCount ? sum / sampleCount : 0;
  String json = "{";
  json += "\"avg10\":" + String(avg10, 2);
  json += ",\"timeInside\":" + String(timeInside / 1000.0, 2);
  json += ",\"timeOutside\":" + String(timeOutside / 1000.0, 2);
  json += ",\"passCount\":" + String(passCount);
  json += ",\"countInsideSwitch\":" + String(countInsideSwitch);
  json += ",\"countOutsideSwitch\":" + String(countOutsideSwitch);
  json += ",\"customDistance\":" + String(customDistance, 2);
  json += ",\"stats\": [";
  for (size_t i = 0; i < stats.size(); i++) {
    if (i > 0) json += ",";
    json += String(stats[i].avg, 2);
  }
  json += "]}";
  server.send(200, "application/json", json);
}

void handleSetDistance() {
  if (server.method() != HTTP_POST) {
    server.send(405, "text/plain", "Method Not Allowed");
    return;
  }

  if (!server.hasArg("plain")) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }

  String body = server.arg("plain");
  int idx = body.indexOf("\"distance\"");
  if (idx < 0) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }
  int colon = body.indexOf(':', idx);
  int comma = body.indexOf(',', colon);
  int endBracket = body.indexOf('}', colon);
  int end = (comma > 0) ? (comma) : (endBracket);
  String valStr = body.substring(colon + 1, end);
  valStr.trim();
  float val = valStr.toFloat();
  if (val <= 0) {
    server.send(400, "text/plain", "Invalid distance");
    return;
  }

  customDistance = val;
  countInside = 0;
  countOutside = 0;
  passCount = 0;
  countInsideSwitch = 0;
  countOutsideSwitch = 0;
  timeInside = 0;
  timeOutside = 0;
  inside = false;
  lastSampleTime = 0;

  server.send(200, "text/plain", "OK");
}

void handleSetFingerprintText() {
  if (server.method() != HTTP_POST) {
    server.send(405, "text/plain", "Method Not Allowed");
    return;
  }

  if (!server.hasArg("plain")) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }

  String body = server.arg("plain");
  int idx = body.indexOf("\"text\"");
  if (idx < 0) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }
  int colon = body.indexOf(':', idx);
  int comma = body.indexOf(',', colon);
  int endBracket = body.indexOf('}', colon);
  int end = (comma > 0) ? (comma) : (endBracket);
  String valStr = body.substring(colon + 1, end);
  valStr.trim();
  
  // 移除文本前后的引号
  if (valStr.startsWith("\"")) valStr.remove(0, 1);
  if (valStr.endsWith("\"")) valStr.remove(valStr.length() - 1);

  fingerprintText = valStr;
  server.send(200, "text/plain", "OK");
}

void setup() {
  pinMode(MOTOR_PIN, OUTPUT);
  digitalWrite(MOTOR_PIN, LOW);  // 默认关闭
  Serial.begin(SENSOR_BAUD);
  while (!Serial) delay(10);
  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255,255,255,0));
  Serial.print("AP IP=");
  Serial.println(WiFi.softAPIP());
  initfingerprint();
  delay(1000);
  server.on("/", handleRoot);
  server.on("/data", handleData);
  server.on("/setDistance", handleSetDistance);
  server.on("/setFingerprintText", handleSetFingerprintText);
  server.begin();
  bleKeyboard.begin();
  // 开机显示 "register" 并调用指纹注册函数

  Wire.begin(SDA_PIN, SCL_PIN);
  // OLED 初始化
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.setRotation(2);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("ScreenLock");
   display.setCursor(100, 22);
   display.setTextSize(1);
  display.println("v1.0");
  display.display();
  delay(3000);

  while (true) {

       display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Register");
   display.setCursor(0, 22);
   display.setTextSize(1);
  display.println("Wait press...");
  display.display();
    // 调用指纹注册函数
    int regResult = register_FP();
    
    if (regResult == 1) {
      // 注册成功，显示 "ok"
             display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Register");
   display.setCursor(0, 22);
   display.setTextSize(1);
  display.println("Succeed !");
  display.display();
     
      break; // 退出循环
    } else {
      // 注册失败，显示 "register again"
                   display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Register");
   display.setCursor(0, 22);
   display.setTextSize(1);
  display.println("Press again...");
  display.display();
     
      delay(2000); // 显示2秒后重新尝试
    }
  }
}

void loop() {
  readSensor();
  server.handleClient();
  // 计算分钟和秒数
  unsigned long workSeconds = timeInside / 1000;
  unsigned long relaxSeconds = timeOutside / 1000;
  unsigned long workMinutes = workSeconds / 60;
  unsigned long relaxMinutes = relaxSeconds / 60;
  unsigned long workRemainingSeconds = workSeconds % 60;
  unsigned long relaxRemainingSeconds = relaxSeconds % 60;
  
  String timeStr = "Work Time: " + String(workMinutes) + ":" + (workRemainingSeconds < 10 ? "0" : "") + String(workRemainingSeconds);
  String timeStr2 = "Relax Time: " + String(relaxMinutes) + ":" + (relaxRemainingSeconds < 10 ? "0" : "") + String(relaxRemainingSeconds);
  // 设置字体（推荐小字体适配 128x32）
  // 显示在屏幕第 1 行（Y 坐标约 12，取决于字体）
                     display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(timeStr.c_str());
   display.setCursor(0, 22);
   display.setTextSize(1);
  display.println(timeStr2.c_str());
  display.display();

}
